<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3.2.1 初识渲染器</title>
</head>
<body>
    
</body>
    <script>
        /**
         * 渲染器的作用就是把虚拟 DOM 渲染为真实 DOM
         * 
         * renderer 的实现思路，总体来说分为三步
         * - 创建元素：把 vnode.tag 作为标签名称来创建 DOM 元素
         * - 为元素添加属性和事件
         * - 处理 children：如果 children 是一个数组，就递归地调用renderer 继续渲染
        */

        // 虚拟 DOM
        const vnode = {
            // 标签名称
            tag: 'div',
            // 标签属性
            props: {
                onClick: () => alert('hello')
            },
            // 子节点
            children: 'click me'
        }

        /**
         * 渲染器
         * @param {Object} vnode 虚拟 DOM
         * @param {HTMLElement} container 挂载点
         * */ 
        function renderer(vnode, container){
            // 使用 vnode.tag 作为标签名称创建 DOM 元素
            const el = document.createElement(vnode.tag)
            // 遍历 vnode.props，将属性、事件添加到 DOM 元素
            for (const key in vnode.props) {
                if (/^on/.test(key)) {
                    // 如果 key 以 on 开头，说明它是事件
                    el.addEventListener(
                        key.substr(2).toLowerCase(), // 事件名称 onClick ---> click
                        vnode.props[key] // 事件处理函数
                    )
                }
            }

            // 处理 children
            if (typeof vnode.children === 'string') {
                // 如果 children 是字符串，说明它是元素的文本子节点
                el.appendChild(document.createTextNode(vnode.children))
            } else if (Array.isArray(vnode.children)) {
                // 递归地调用 renderer 函数渲染子节点，使用当前元素 el 作为挂载点
                vnode.children.forEach(child => renderer(child, el))
            }

            // 将元素添加到挂载点下
            container.appendChild(el)
        }

        renderer(vnode, document.body) // body 作为挂载点

        
    </script>
</html>